﻿// #pragma once
// Copyright (c) lanyeo 2020-2021
// Licenced under MIT license. See https://opensource.org/licenses/MIT for details.
// code style
// 1. use forward declaration (尽可能使用前置声明)
// 2. include file sequence [other project>c>c++>third>self project]
//

#include <condition_variable>

namespace fist
{
    template <typename T>
    class ListProCon {
    private:
        std::list<T> m_queue;
        std::mutex m_mutex;//全局互斥锁
        std::condition_variable_any m_notEmpty;//全局条件变量（不为空）
        std::condition_variable_any m_notFull;//全局条件变量（不为满）
        int m_maxSize;//队列最大容量

    public:
        //队列为空
        bool isEmpty() const {
            return m_queue.empty();
        }
        //队列已满
        bool isFull() const {
            return m_queue.size() == m_maxSize;
        }

    public:
        ListProCon(int maxSize) : m_maxSize(maxSize) {
        }
        ListProCon() : m_maxSize(1000) {

        }

        virtual ~ListProCon() {

        }

        void produce(const T& v) {
            std::unique_lock<std::mutex> locker(m_mutex);
            while(isFull()) {
                //生产者等待"产品队列缓冲区不为满"这一条件发生.
                m_notFull.wait(m_mutex);
            }
            //往队列里面生产一个元素,同时通知不为空这个信号量
            m_queue.push_back(v);
            m_notEmpty.notify_one();
        }
        void consume(T& v) {
            std::unique_lock<std::mutex> locker(m_mutex);
            while(isEmpty()) {
                // 消费者等待"产品队列缓冲区不为空"这一条件发生.
                m_notEmpty.wait(m_mutex);
            }
            //在队列里面消费一个元素,同时通知队列不满这个信号量
            v = m_queue.front();
            m_queue.pop_front();
            m_notFull.notify_one();
        }
    };
}